package com.chaoyer.cynet.common.route;


import com.chaoyer.cynet.common.annotation.Delete;
import com.chaoyer.cynet.common.annotation.Get;
import com.chaoyer.cynet.common.annotation.Post;
import com.chaoyer.cynet.common.annotation.Put;
import com.chaoyer.cynet.common.context.HandlerContext;
import com.chaoyer.cynet.common.utils.ReflectUtils;
import com.google.common.collect.Maps;
import io.netty.handler.codec.http.HttpMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class RouterMapping {

    private static final Logger logger = LoggerFactory.getLogger(RouterMapping.class);

    private static final HashMap<HttpMethod, HashMap<String, HandlerContext>> routerMap = Maps.newHashMap();

    public static HashMap<String, HandlerContext> get(HttpMethod method) {
        return routerMap.get(method);
    }


    /*
    *  获取spring容器中自定义的路由注解类
    * */
    public static void register(ApplicationContext ac) throws Exception {

        long startTime = System.currentTimeMillis();

        Map<String, Object> controllerBeans = ac.getBeansWithAnnotation(Controller.class);

        Iterator<String> iter = controllerBeans.keySet().iterator();
        HashMap<String, HandlerContext> optionMap = Maps.newHashMap();
        HashMap<String, HandlerContext> getMap = Maps.newHashMap();
        HashMap<String, HandlerContext> postMap = Maps.newHashMap();
        HashMap<String, HandlerContext> putMap = Maps.newHashMap();
        HashMap<String, HandlerContext> deleteMap = Maps.newHashMap();
        while (iter.hasNext()) {
            Object bean = ReflectUtils.getTarget(controllerBeans.get(iter.next()));
            Method[] methods = bean.getClass().getDeclaredMethods();
            for (Method method : methods) {
                Annotation[] annotations = method.getDeclaredAnnotations();
                for (Annotation a : annotations) {
                    // get
                    if (a.annotationType().equals(Get.class)) {
                        String value = ((Get) a).value();
                        if (getMap.containsKey(value)) {
                            throw new IllegalAccessException("" + bean.getClass().getSimpleName() +
                                    " {[" + value + "],methods=[Get]}:" +
                                    " There is already '" + getMap.get(value).getClazz().getClass().getSimpleName() + "' bean method");
                        }
                        getMap.put(value, new HandlerContext(bean, method));
                        logger.info("Register route: {} , {} , {}","GET",value,bean.getClass().getSimpleName());
                    }
                    // post
                    if (a.annotationType().equals(Post.class)) {
                        String value = ((Post) a).value();
                        if (postMap.containsKey(value)) {
                            throw new IllegalAccessException("" + bean.getClass().getSimpleName() +
                                    " {[" + value + "],methods=[GhostPost]}:" +
                                    " There is already '" + postMap.get(value).getClazz().getClass().getSimpleName() + "' bean method");
                        }
                        postMap.put(value, new HandlerContext(bean, method));
                        logger.info("Register route: {} , {} , {}","POST",value,bean.getClass().getSimpleName());

                    }
                    // put
                    if (a.annotationType().equals(Put.class)) {
                        String value = ((Put) a).value();
                        if (putMap.containsKey(value)) {
                            throw new IllegalAccessException("" + bean.getClass().getSimpleName() +
                                    " {[" + value + "],methods=[put]}:" +
                                    " There is already '" + putMap.get(value).getClazz().getClass().getSimpleName() + "' bean method");
                        }
                        putMap.put(value, new HandlerContext(bean, method));
                        logger.info("Register route: {} , {} , {}","PUT",value,bean.getClass().getSimpleName());

                    }

                    // delete
                    if (a.annotationType().equals(Delete.class)) {
                        String value = ((Delete) a).value();
                        if (deleteMap.containsKey(value)) {
                            throw new IllegalAccessException("" + bean.getClass().getSimpleName() +
                                    " {[" + value + "],methods=[delete]}:" +
                                    " There is already '" + deleteMap.get(value).getClazz().getClass().getSimpleName() + "' bean method");
                        }
                        deleteMap.put(value, new HandlerContext(bean, method));
                        logger.info("Register route: {} , {} , {}","DELETE",value,bean.getClass().getSimpleName());
                    }
                }
            }
        }
        routerMap.put(HttpMethod.OPTIONS,optionMap);
        routerMap.put(HttpMethod.GET, getMap);
        routerMap.put(HttpMethod.POST, postMap);
        routerMap.put(HttpMethod.PUT, putMap);
        routerMap.put(HttpMethod.DELETE, deleteMap);
        logger.info("register router spend time {}", System.currentTimeMillis() - startTime);
    }

}
